﻿///@author Rafał Hazan
///@email  rafal.hazan@gmail.com
#include <fstream>
#include <sstream>
#include <ctime>
#pragma comment (lib, "winmm.lib")
#include <windows.h>
#include <mmsystem.h>

#include "GraphBuilder.h"
#include "BadGraphFormatException.h"
#include "MatrixGraph.h"

#include "PopulationInitializer.h"
#include "EvolutionaryAlgorithm.h"
#include "CliqueInitializer.h"
#include "ProgressStopCondition.h"
#include "TournamentSelect.h"
#include "BetterFullCrossover.h"
#include "MultipointMutation.h"
#include "EliteReplacement.h"
#include "Configuration.h"
#include "Genotype.h"
#include "Configuration.h"
#include "TimeHelper.h"

//tutaj wartosci sa shardcodowane, ale ponizej zostana uaktualnione
unsigned int Configuration::u = 300;
int Configuration::lambda = 1;
double Configuration::pc = 0.8000000000000005;
unsigned int Configuration::mutateNo = 50;
//double Configuration::mutateProb = 0.9998;
int Configuration::stopChecksNo = 100;
unsigned int Configuration::tournamentGroupNo = 200;
int Configuration::selectPairs = 2;

PopulationInitializer & a = CliqueInitializer();
StopCondition & b = ProgressStopCondition();
SelectOperator & c = TournamentSelect();
CrossoverOperator & d = BetterFullCrossover();
MutationOperator & e = MultipointMutation();
ReplacementOperator & f = EliteReplacement();

std::ostream & operator<<(std::ostream & output, const Genotype & gen) {
	output << "Genotype, ones: [ ";
	for(std::set<int>::const_iterator iter = gen.gens.begin(); iter != gen.gens.end(); ++iter)
	{
		output << *iter << ", ";
	}
	output << "]";
    return output;
}

int main(int argc, const char ** argv)
{
	if (argc != 9)
	{
		std::cerr << "Nieprawidlowe argumenty wywolania programu." << std::endl << "uzycie:" << std::endl << 
			"nazwa pliku grafu" << std::endl <<
			"wielkosc populacji glownej" << std::endl <<
			"wielkosc populacji tymczasowej" << std::endl <<
			"prawdopodobienstwo krzyzowania" << std::endl <<
			"liczba mutowanych bitow" << std::endl <<
			"liczba iteracji algorytmu bez lepszych rozwiazach, po ktorych nastapi zakonczenie" << std::endl <<
			"liczba liczba par wybieranych operatorem selekcji" << std::endl <<
			"wielkosc grupy turniejowej" << std::endl << "wartosci procentowe oznaczaja skalowanie wspolczynnikow wzgledem wielkosci grafu";
		return 0;
	}

	std::stringstream ss;
	std::string filename = argv[1];

	std::ifstream file(filename, std::ios::in);
	GraphBuilder graphBuilder;
	MatrixGraph * graph;
	try
	{
		graph = graphBuilder.buildFromFile(file);
	}
	catch(BadGraphFormatException ex)
	{
		std::cerr << "Nieprawidlowe dane, kod bledu: " << std::endl << ex.what() << std::endl;
		return 0;
	}

	ss << argv[2];
	double tmp;
	ss >> tmp;
	if (tmp < 1.0)
	{
		Configuration::u = graph->getVSize() * tmp;
		if (Configuration::u < 1)
		{
			Configuration::u = 1;
		}
	}
	else
	{
		Configuration::u = tmp;
	}
	ss.clear();
	ss << argv[3];
	ss >> tmp;
	if (tmp < 1.0)
	{
		Configuration::lambda = graph->getVSize() * tmp;
	}
	else
	{
		Configuration::lambda = tmp;
	}
		ss.clear();
	ss << argv[4];
	ss >> tmp;
	Configuration::pc = tmp;
	ss.clear();
	ss << argv[5];
	ss >> tmp;
	if (tmp < 1.0)
	{
		Configuration::mutateNo = graph->getVSize() * tmp;
	}
	else
	{
		Configuration::mutateNo = tmp;
	}
	ss.clear();
	ss << argv[6];
	ss >> tmp;
	if (tmp < 1.0)
	{
		Configuration::stopChecksNo = graph->getVSize() * tmp;
	}
	else
	{
		Configuration::stopChecksNo = tmp;
	}
	ss.clear();
	ss << argv[7];
	ss >> tmp;
	if (tmp < 1.0)
	{
		Configuration::selectPairs = graph->getVSize() * tmp;
	}
	else
	{
		Configuration::selectPairs = tmp;
	}
	ss.clear();
	ss << argv[8];
	ss >> tmp;
	if (tmp < 1.0)
	{
		Configuration::tournamentGroupNo = graph->getVSize() * tmp;
	}
	else
	{
		Configuration::tournamentGroupNo = tmp;
	}
	//std::cout << "u " << Configuration::u << std::endl;
	//std::cout << "lambda " << Configuration::lambda << std::endl;
	//std::cout << "pc " << Configuration::pc << std::endl;
	//std::cout << "mutateNo " << Configuration::mutateNo << std::endl;
	//std::cout << "stopChecksNo " << Configuration::stopChecksNo << std::endl;
	//std::cout << "tournamentGroupNo " << Configuration::tournamentGroupNo << std::endl;

	EvolutionaryAlgorithm evoluty = EvolutionaryAlgorithm(a, b, c, d, e, f);

	unsigned long seconds = timeGetTime();//time (NULL);
	evoluty.perform(*graph);
	unsigned long secondsAfter = timeGetTime();//time (NULL);

	std::cout << "=TIME=" << (secondsAfter - seconds) << std::endl;
	std::cout << "=LOOPS=" << EvolutionaryAlgorithm::iterationNo << std::endl;
	std::cout << "=BEST=" << *evoluty.population.begin();

	std::cout << std::endl;
    //system("PAUSE");
	file.close();
    return 0;   
}